package com.fpd.interceptor;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.fpd.constant.Constants;
import com.fpd.constant.SystemConstant;
import com.fpd.exceptions.NoLoginException;
import com.fpd.model.entity.SysUser;
import com.fpd.tools.TokenUtil;
import com.fpd.tools.Tool;

/**
 * @desc 验证token的拦截器
 * @author wujiangbo
 * @date 2019年11月6日 上午8:53:55
 */
public class AuthenticationInterceptor implements HandlerInterceptor {

	//@Autowired
	//protected TokenMapper tokenMapper;

	@Autowired
	private RedisTemplate<Object, Object> redisTemplate;

	@Autowired
	private TokenUtil tokenUtil;

	@Value("${token.tokenTimeout}")
	private Integer tokenTimeout;

	@Override
	public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
		// 如果不是映射到方法直接通过
		if (!(object instanceof HandlerMethod)) {
			return true;
		}
		HandlerMethod handlerMethod = (HandlerMethod) object;
		Method method = handlerMethod.getMethod();
		String methodName = method.getName();
		String whiteList = "captcha,login,uiConfiguration,swaggerResources,getDocumentation,securityConfiguration,selectBaseInfoByPhone,thirdLawyerPrint,synThirdCase,creditScore,creditScoreInsert,importCust,list,sendMobileMsg,synHfq,synHfq2";
		if (whiteList.contains(methodName)) {
			// 请求白名单方法，就放行，其余方法需要验证token
			return true;
		}
		// 获取当前用户请求头信息中的token信息
		String token = this.tokenUtil.getToken();
		SysUser user = this.tokenUtil.getRedisUser();
		if (Tool.isBlank(token)) {
			throw new NoLoginException("请求头信息中无token，请重新登录");
		}
		String token_key = Constants.TOKEN_KEY_STRING + token;
		// 获取当前用户在Redis中的token信息，然后与传来的对比
		String redis_token = (String) redisTemplate.opsForValue().get(token_key);
		String userIdToken = (String) redisTemplate.opsForValue().get(user.getUserId());
		if (Tool.isBlank(redis_token) || Tool.isBlank(userIdToken)) {
			throw new NoLoginException("token失效，请重新登录");
		}
		if (!token.equals(redis_token)) {
			throw new NoLoginException("token错误");
		}
		if (!token.equals(userIdToken)) {
			throw new NoLoginException("请重新登录");
		}
		// 重置token失效时间
		this.redisTemplate.expire(token_key, tokenTimeout, TimeUnit.MINUTES);
		this.redisTemplate.expire(user.getUserId(), tokenTimeout, TimeUnit.MINUTES);

		String userInfoRedisKey = SystemConstant.REDIS_USER_INFO_KEY + token;
		Map<Object, Object> map = this.redisTemplate.opsForHash().entries(userInfoRedisKey);
		if (map == null) {
			throw new NoLoginException("无用户信息，请重新登录");
		}
		// Redis中会话的用户信息对象
		SysUser userInfo = (SysUser) map.get(SystemConstant.MAP_USER_INFO_KEY);
		if (userInfo == null) {
			throw new NoLoginException("无用户信息，请重新登录");
		}
		// 重置用户信息失效时间
		this.redisTemplate.expire(userInfoRedisKey, tokenTimeout, TimeUnit.MINUTES);

		// 检验用户是否在线（根据userId在redis查不到token就表示被强制下线了）
		String onLineToken = (String) redisTemplate.opsForValue().get(userInfo.getUserId());
		if (Tool.isBlank(onLineToken)) {
			throw new NoLoginException("请重新登录");
		}
		return true;
	}

	@Override
	public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
	}

	@Override
	public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
	}
}
